﻿using System;
using System.Collections.Generic;
using System.Text;
using PacketRush.Core;

namespace PacketRush.Services.UserManagement
{
    public class ClientNetUserService : NetUserService, INetService
    {
        private PacketWriter _PacketWriter = new PacketWriter();
        private Queue<Packet> _OutgoingPackets = new Queue<Packet>(4);
        /// <summary>
        /// Gets the local users name
        /// </summary>
        public string Name { get; private set; }

        public ClientNetUserService(NetClient netClient, string name)
        {
            Name = name;

            netClient.RemoteConnected += new EventHandler<NetEventArgs>(NetClient_Connected);
            netClient.RemoteDisconnected += new EventHandler<NetEventArgs>(NetClient_Disconnected);
            netClient.LocalConnected += new EventHandler<NetEventArgs>(NetClient_LocalConnected);
        }
        public void DeliverPacket(Packet packet)
        {
            //
            // This packet should contain a list of connected users and their names
            //
            ProcessUserListPacket(packet);

        }

        private void ProcessUserListPacket(Packet packet)
        {
            PacketReader reader = new PacketReader(packet);
            int numUsers = reader.ReadInt32();

            for (int i = 0; i < numUsers; i++)
            {
                int id = reader.ReadUInt16();
                string name = reader.ReadString(Encoding.UTF8);

                if (!Users.ContainsKey(id))
                {
                    Users.Add(id, new NetUser() { ConnectionId = id, Name = name });
                    OnUserAdded(id);
                }
                else
                {
                    string oldName = Users[id].Name;
                    if (oldName != name) OnUserChangedName(id, oldName, name);
                    Users[id].Name = name;
                }
            }
        }

        public Packet CollectPacket()
        {
            if (_OutgoingPackets.Count > 0)
            {
                return _OutgoingPackets.Dequeue();
            }

            return null;
        }

        void NetClient_LocalConnected(object sender, NetEventArgs e)
        {
            // Let everyone know our name
            SendNameChangePacket();

            //
            // Lets add us to the User list
            //
            Users.Add(e.ConnectionId, new NetUser() { ConnectionId = e.ConnectionId, Name = Name });
            OnUserAdded(e.ConnectionId);
        }

        void NetClient_Disconnected(object sender, NetEventArgs e)
        {
            RemoveUser(e.ConnectionId);
        }

        /// <summary>
        /// Remove a user from the Users list that matches the given id
        /// </summary>
        /// <param name="id">The id to remove the user by</param>
        private void RemoveUser(int id)
        {
            if (Users.ContainsKey(id))
            {
                OnUserRemoved(id);
                Users.Remove(id);
            }
        }

        void NetClient_Connected(object sender, NetEventArgs e)
        {

        }

        /// <summary>
        /// Queues up a packet to send that contains this local clients name
        /// </summary>
        private void SendNameChangePacket()
        {
            _PacketWriter.Reset();
            _PacketWriter.Write(Name, Encoding.UTF8);
            _OutgoingPackets.Enqueue(_PacketWriter.ToPacket(PacketFlags.Reliable));
        }

        /// <summary>
        /// Changes the local users name and informs the server with the new name
        /// </summary>
        /// <param name="newName">The new name of this local user</param>
        public void ChangeName(string newName)
        {
            Name = newName;

            SendNameChangePacket();
        }
    }
}
